This is an analysis of a dataset generated in the lab containing septum from E11.5 PGK-Cre;Rosa26YFP and E12.5 Dbx1-Cre;Rosa26Tomato embryos Cells were prepared by Matthieu Moreau & Frédéric Causeret
Libraries were generated by Matthieu Moreau & Frédéric Causeret
Sequencing was achieved at the genomics platform of Imagine
Reads were aligned on the mm10 genome to which were added: - LacZ-SV40
- Tomato-WPRE-bGH

1 Load libraries

library(Seurat)
library(dplyr)
library(patchwork)
library(cowplot)
library(ggplot2)
library(ggExtra)

library(Matrix)
library(RColorBrewer)
library(viridis)
library(wesanderson)
library(MetBrewer)


# Set ggplot theme as classic
theme_set(theme_classic())

2 Load the dataset and calculate QC metrics

2.1 Initialize a Seurat object from the raw filtered gene/bc matrix

# Load the raw filtered_gene_bc_matrix outputed by Cell Ranger
Countdata <- Read10X(data.dir = "/shared/ifbstor1/home/fcauseret/Septum/filtered_gene_bc_matrices/")

# Initialize the Seurat object
Septum <- CreateSeuratObject(counts = Countdata,
                               min.cells = 3,
                               min.features = 800,
                               project = "Septum")

Septum$Barcodes <- colnames(Septum)

dim(Septum)
## [1] 17280  5825
rm(Countdata)

2.2 Calculate percentage of mitochondrial and ribosomal counts

# Percent of mitochondrial counts
Septum[["percent.mt"]] <- PercentageFeatureSet(Septum, pattern = "^mt-")

# Percent of ribosomal counts
Septum[["percent.rb"]] <- PercentageFeatureSet(Septum, pattern = "(^Rpl|^Rps|^Mrp)")

2.3 Cell Quality according to the mitochondrial RNA percentage in the cells

# Filter cells based on these thresholds
Cell.QC.Stat <- Septum@meta.data
max.mito.thr <- median(Cell.QC.Stat$percent.mt) + 3*mad(Cell.QC.Stat$percent.mt)
min.mito.thr <- median(Cell.QC.Stat$percent.mt) - 3*mad(Cell.QC.Stat$percent.mt)
Cell.QC.Stat <- Cell.QC.Stat %>% filter(percent.mt < max.mito.thr) %>% filter(percent.mt > min.mito.thr)

Septum@meta.data$Cell.quality <- ifelse(Septum@meta.data$percent.mt > min.mito.thr & Septum@meta.data$percent.mt < max.mito.thr, "High Quality", "Low Quality")

table(Septum$Cell.quality)
## 
## High Quality  Low Quality 
##         5444          381
rm(Cell.QC.Stat, max.mito.thr, min.mito.thr)

2.4 Plot basic QC metrics

#Violin plot 
VlnPlot(Septum, features = c("nFeature_RNA", "nCount_RNA", "percent.mt", "percent.rb"), ncol = 4, group.by="Cell.quality")

2.4.1 Plot more QC metrics

# Relation between nCount_RNA and nFeatures_RNA detected with cell quality parameter
p1 <- ggplot(Septum@meta.data, aes(x=nCount_RNA, y=nFeature_RNA)) + geom_point(aes(color=Cell.quality), size=0.1) + geom_smooth(method="lm")
p1 <- ggMarginal(p1, type = "histogram", fill="lightgrey")

p2 <- ggplot(Septum@meta.data, aes(x=log10(nCount_RNA), y=log10(nFeature_RNA))) + geom_point(aes(color=Cell.quality), size=0.1) + geom_smooth(method="lm")
p2 <- ggMarginal(p2, type = "histogram", fill="lightgrey")

# Relation between nFeatures_RNA and the mitochondrial RNA percentage detected with cell quality parameter
p3 <- ggplot(Septum@meta.data, aes(x=nFeature_RNA, y=percent.mt, color=Cell.quality)) + geom_point(size=0.1)
p3 <- ggMarginal(p3, type = "histogram", fill="lightgrey", bins=100) 
    
plot_grid(plotlist = list(p1,p2,p3), ncol=3, align='h', rel_widths = c(1, 1, 1))

rm(p1, p2, p3)

2.5 Cell Cycle Scoring

# Assign cell-cycle scores
s.genes <- c("Mcm5", "Pcna", "Tym5", "Fen1", "Mcm2", "Mcm4", "Rrm1", "Ung", "Gins2", "Mcm6", "Cdca7", "Dtl", "Prim1", "Uhrf1", "Mlf1ip", "Hells", "Rfc2", "Rap2", "Nasp", "Rad51ap1", "Gmnn", "Wdr76", "Slbp", "Ccne2", "Ubr7", "Pold3", "Msh2", "Atad2", "Rad51", "Rrm2", "Cdc45", "Cdc6", "Exo1", "Tipin", "Dscc1", "Blm", " Casp8ap2", "Usp1", "Clspn", "Pola1", "Chaf1b", "Brip1", "E2f8")
g2m.genes <- c("Hmgb2", "Ddk1","Nusap1", "Ube2c", "Birc5", "Tpx2", "Top2a", "Ndc80", "Cks2", "Nuf2", "Cks1b", "Mki67", "Tmpo", " Cenpk", "Tacc3", "Fam64a", "Smc4", "Ccnb2", "Ckap2l", "Ckap2", "Aurkb", "Bub1", "Kif11", "Anp32e", "Tubb4b", "Gtse1", "kif20b", "Hjurp", "Cdca3", "Hn1", "Cdc20", "Ttk", "Cdc25c", "kif2c", "Rangap1", "Ncapd2", "Dlgap5", "Cdca2", "Cdca8", "Ect2", "Kif23", "Hmmr", "Aurka", "Psrc1", "Anln", "Lbr", "Ckap5", "Cenpe", "Ctcf", "Nek2", "G2e3", "Gas2l3", "Cbx5", "Cenpa")

Septum <- CellCycleScoring(Septum,
                             s.features = s.genes,
                             g2m.features = g2m.genes,
                             set.ident = T)
table(Septum$Phase)
## 
##   G1  G2M    S 
## 2691 1376 1758
rm(s.genes, g2m.genes)

3 Normalize counts

# LogNormalize the gene expression matrix (global-scaling normalization method)
Septum <- NormalizeData(Septum, normalization.method = "LogNormalize", scale.factor = 10000)

4 Identification of highly variable features (feature selection)

Septum <- FindVariableFeatures(Septum, selection.method = "vst", nfeatures = 2000)

# Identify the 10 most highly variable genes
top20 <- head(VariableFeatures(Septum), 20)

# Plot variable features with and without labels
plot1 <- VariableFeaturePlot(Septum) + theme(legend.position = "top")
plot2 <- LabelPoints(plot = plot1, points = top20, repel = T) + theme(legend.position = "none")
plot_grid(plotlist = list(plot1,plot2), ncol=2, align='h', rel_widths = c(1, 1))

rm(top20, plot1, plot2)

5 Scaling the data

# Linear transformation : Pre-processing step for dimensional reduction like PCA 
Septum <- ScaleData(Septum)

6 Perform linear dimensional reduction

Septum <- RunPCA(Septum, features = VariableFeatures(object = Septum))
# Examine and visualize PCA results a few different ways
print(Septum[["pca"]], dims = 1:5, nfeatures = 5)
## PC_ 1 
## Positive:  Mllt11, Tagln3, Rtn1, Tubb3, Tuba1a 
## Negative:  Hmgb2, Anp32b, Tuba1b, Dek, Phgdh 
## PC_ 2 
## Positive:  Alas2, Gypa, Car2, Acp5, Rhd 
## Negative:  Tubb2b, Pkm, Set, Map1b, Tuba1a 
## PC_ 3 
## Positive:  Fgf8, Fgf17, Serpinh1, Sparc, Zic4 
## Negative:  Alas2, Gypa, Pantr1, Car2, Efnb1 
## PC_ 4 
## Positive:  Arl6ip1, Cenpf, Ube2c, Nusap1, Prc1 
## Negative:  Ung, Pkm, Slc25a5, Mcm2, Mcm6 
## PC_ 5 
## Positive:  Cdkn1c, Hes6, Mfng, Dlk1, Rgs16 
## Negative:  Socs2, Gm3764, Wnt7b, Gas1, Thra
VizDimLoadings(Septum, dims = 1:2, reduction = "pca")

DimHeatmap(Septum, dims = 1:6, cells = 500, balanced = TRUE)

7 Determine the ‘dimensionality’ of the dataset

#  More approximate techniques such as those implemented in ElbowPlot() can be used to reduce computation time
Septum <- JackStraw(Septum, num.replicate = 100)
Septum <- ScoreJackStraw(Septum, dims = 1:20)

# JackStrawPlot
JackStrawPlot(Septum, dims = 1:20)

#ElbowPlot
ElbowPlot(Septum)

8 Run non-linear dimensional reduction (UMAP)

Septum <- RunUMAP(Septum, dims = 1:20)
DimPlot(Septum, reduction = "umap", label = TRUE, label.size = 3, pt.size = 0.1) + NoAxes()

9 Cluster the cells

Septum <- FindNeighbors(Septum, dims = 1:20)
Septum <- FindClusters(Septum, resolution = 1.5)
## Modularity Optimizer version 1.3.0 by Ludo Waltman and Nees Jan van Eck
## 
## Number of nodes: 5825
## Number of edges: 181940
## 
## Running Louvain algorithm...
## Maximum modularity in 10 random starts: 0.8266
## Number of communities: 24
## Elapsed time: 0 seconds
# Visualize clusters
DimPlot(Septum, reduction = "umap", label = TRUE, label.size = 3, pt.size = 0.1) + NoAxes() + ggtitle(paste(dim(Septum)[2], " septum cells")) 

10 Remove low quality, blood and meninges cells

DimPlot(Septum, reduction = "umap", label = TRUE, label.size = 3, pt.size = 0.1, group.by="Cell.quality") + NoAxes()

FeaturePlot(Septum, features = c("Hba-a1", "Col3a1"), order = T, 
            cols = c("grey90", brewer.pal(9,"YlOrRd"))) & NoLegend() & NoAxes()

Septum <- subset(Septum, idents = c(8, 20, 22), invert = TRUE)

DimPlot(Septum, reduction = "umap", label = TRUE, label.size = 3, pt.size = 0.1) + NoAxes() + ggtitle(paste(dim(Septum)[2], " cells after filtering")) 

11 Export files for Spring

11.1 Export raw expression matrix and gene list for spring plot generation

# Generate Spring dimensionality reduction
ExprsMatrix <- as.matrix(GetAssayData(Septum))
exprData <- Matrix(ExprsMatrix, sparse = TRUE)
writeMM(exprData, "ExprData.mtx")
## NULL
Genelist <- row.names(ExprsMatrix)
write.table(Genelist, "Genelist.csv", sep="\t", col.names = F, row.names = F)
rm(ExprsMatrix, exprData, Genelist)

11.2 Export continuous metadata

S.Score <- c("S.Score",Septum@meta.data$S.Score)
S.Score <- paste(S.Score, sep=",", collapse=",")

G2M.Score <- c("G2M.Score",Septum@meta.data$G2M.Score)
G2M.Score <- paste(G2M.Score, sep=",", collapse=",")

Percent.mt <- c("Percent.mt", Septum$percent.mt)
Percent.mt <- paste(Percent.mt, sep = ",", collapse = ",")

Percent.rb <- c("Percent.rb", Septum$percent.rb)
Percent.rb <- paste(Percent.rb, sep = ",", collapse = ",")

nCount <- c("nCount", Septum$nCount_RNA)
nCount <- paste(nCount, sep = ",", collapse = ",") 

nFeature <- c("nFeature", Septum$nFeature_RNA)
nFeature <- paste(nFeature, sep = ",", collapse = ",") 

ColorTrack <- rbind(S.Score, G2M.Score, Percent.mt, Percent.rb, nCount, nFeature)
write.table(ColorTrack, "ColorTrack.csv", quote =F, row.names = F, col.names = F)

rm(S.Score, G2M.Score, Percent.mt, Percent.rb, nCount, nFeature, ColorTrack)

11.3 Export discrete metadata

Seurat.clusters <- c("Seurat Clusters", paste0("Cluster",as.character(Septum@meta.data$seurat_clusters)))
Seurat.clusters <- paste(Seurat.clusters, sep=",", collapse=",")

Phase <- c("Phase", Septum@meta.data$Phase)
Phase <- paste(Phase, sep=",", collapse=",")

Quality <- c("Cell Quality", Septum$Cell.quality) 
Quality <- paste(Quality, sep = ",", collapse = ",") 

Cellgrouping <- rbind(Seurat.clusters, Phase, Quality)
write.table(Cellgrouping, "Cellgrouping.csv", quote =F, row.names = F, col.names = F)

rm(Cellgrouping, Seurat.clusters, Phase, Quality)

ExprData.mtx, Genelist.csv, ColorTrack.csv and Cellgrouping.csv are then used as input for the Spring App Cell coordinates of the Spring dimensionality reduction as well as doublet score are then downloaded

12 Import Spring doublet score (scrubblet) and remove doublets

doublet.score <- read.table("/shared/ifbstor1/home/fcauseret/Septum/doublet_results.tsv", header = T)
doublet.score <- filter(doublet.score, Observed_or_Simulated == "Observed")
rownames(doublet.score) <- Septum$Barcodes
Septum@meta.data$doublet.score <-doublet.score$Score
VlnPlot(object = Septum, features = "doublet.score", pt.size = 0.2) + geom_hline(yintercept = 0.4, linetype="dashed") + FeaturePlot(Septum, features = c("doublet.score"), order = T,
            cols = c("grey90", brewer.pal(9,"YlOrRd")))

Septum <- subset(Septum, subset = doublet.score < 0.4)

DimPlot(Septum, reduction = "umap", label = TRUE, label.size = 3, pt.size = 0.1) + NoAxes() + ggtitle(paste(dim(Septum)[2], " cells after doublets removal")) 

13 Import Spring coordinates

Coordinates <- read.table("/shared/ifbstor1/home/fcauseret/Septum/coordinates.txt", sep = ",", header = F)[,c(2,3)]
rownames(Coordinates) <- Septum$Barcodes
colnames(Coordinates) <- paste0("Spring_", 1:2)

# We will now store this as a custom dimensional reduction : spring
Septum[["Spring"]] <- CreateDimReducObject(embeddings = as.matrix(Coordinates), key = "Spring_", assay = DefaultAssay(Septum))

# Symmetry transform of the coordinates

Spring.Sym <- function(x){
  x = abs(max(Coordinates[,2])-x)
 }

Coordinates[,2] <- sapply(Coordinates[,2] , function(x) Spring.Sym(x))

Septum[["Spring"]] <- CreateDimReducObject(embeddings = as.matrix(Coordinates), key = "Spring_", assay = DefaultAssay(Septum))

rm(Coordinates, doublet.score)


# Spring visualization 
DimPlot(Septum, reduction = "Spring", pt.size = 0.2, label = T, label.size = 3) + NoAxes() + NoLegend()

FeaturePlot(Septum,
            features = c("Eomes", "Tbr1", "Isl1", "Trp73", "Onecut2", "Dbx1", "dtTomato", "Pcdh8", "Spon1"),
            reduction = "Spring",
            ncol = 3,
            order = T,
            cols = c("grey90", brewer.pal(9,"YlGnBu")))  & NoLegend() & NoAxes()

14 Save object

saveRDS(Septum, "/shared/ifbstor1/home/fcauseret/Septum/Septum.RDS")

15 Session Info

#date
format(Sys.time(), "%d %B, %Y, %H,%M")
## [1] "09 April, 2022, 19,11"
#Packages used
sessionInfo()
## R version 4.1.1 (2021-08-10)
## Platform: x86_64-conda-linux-gnu (64-bit)
## Running under: CentOS Linux 7 (Core)
## 
## Matrix products: default
## BLAS/LAPACK: /shared/ifbstor1/software/miniconda/envs/r-4.1.1/lib/libopenblasp-r0.3.18.so
## 
## locale:
##  [1] LC_CTYPE=en_US.UTF-8       LC_NUMERIC=C              
##  [3] LC_TIME=en_US.UTF-8        LC_COLLATE=en_US.UTF-8    
##  [5] LC_MONETARY=en_US.UTF-8    LC_MESSAGES=en_US.UTF-8   
##  [7] LC_PAPER=en_US.UTF-8       LC_NAME=C                 
##  [9] LC_ADDRESS=C               LC_TELEPHONE=C            
## [11] LC_MEASUREMENT=en_US.UTF-8 LC_IDENTIFICATION=C       
## 
## attached base packages:
## [1] stats     graphics  grDevices utils     datasets  methods   base     
## 
## other attached packages:
##  [1] MetBrewer_0.2.0    wesanderson_0.3.6  viridis_0.6.2      viridisLite_0.4.0 
##  [5] RColorBrewer_1.1-2 Matrix_1.3-4       ggExtra_0.9        ggplot2_3.3.5     
##  [9] cowplot_1.1.1      patchwork_1.1.1    dplyr_1.0.7        SeuratObject_4.0.4
## [13] Seurat_4.1.0      
## 
## loaded via a namespace (and not attached):
##   [1] Rtsne_0.15            colorspace_2.0-3      deldir_1.0-6         
##   [4] ellipsis_0.3.2        ggridges_0.5.3        rstudioapi_0.13      
##   [7] spatstat.data_2.1-2   farver_2.1.0          leiden_0.3.9         
##  [10] listenv_0.8.0         ggrepel_0.9.1         fansi_1.0.2          
##  [13] codetools_0.2-18      splines_4.1.1         knitr_1.37           
##  [16] polyclip_1.10-0       jsonlite_1.7.3        ica_1.0-2            
##  [19] cluster_2.1.2         png_0.1-7             uwot_0.1.11          
##  [22] shiny_1.7.1           sctransform_0.3.3     spatstat.sparse_2.1-0
##  [25] compiler_4.1.1        httr_1.4.2            assertthat_0.2.1     
##  [28] fastmap_1.1.0         lazyeval_0.2.2        cli_3.2.0            
##  [31] later_1.3.0           htmltools_0.5.2       tools_4.1.1          
##  [34] igraph_1.2.11         gtable_0.3.0          glue_1.6.2           
##  [37] RANN_2.6.1            reshape2_1.4.4        Rcpp_1.0.8.3         
##  [40] scattermore_0.7       jquerylib_0.1.4       vctrs_0.3.8          
##  [43] nlme_3.1-153          lmtest_0.9-39         xfun_0.30            
##  [46] stringr_1.4.0         globals_0.14.0        mime_0.12            
##  [49] miniUI_0.1.1.1        lifecycle_1.0.1       irlba_2.3.5          
##  [52] goftest_1.2-3         future_1.23.0         MASS_7.3-54          
##  [55] zoo_1.8-9             scales_1.1.1          spatstat.core_2.3-2  
##  [58] promises_1.2.0.1      spatstat.utils_2.3-0  parallel_4.1.1       
##  [61] yaml_2.2.2            reticulate_1.22       pbapply_1.5-0        
##  [64] gridExtra_2.3         sass_0.4.0            rpart_4.1-15         
##  [67] stringi_1.7.6         highr_0.9             rlang_1.0.1          
##  [70] pkgconfig_2.0.3       matrixStats_0.61.0    evaluate_0.14        
##  [73] lattice_0.20-45       ROCR_1.0-11           purrr_0.3.4          
##  [76] tensor_1.5            labeling_0.4.2        htmlwidgets_1.5.4    
##  [79] tidyselect_1.1.1      parallelly_1.30.0     RcppAnnoy_0.0.19     
##  [82] plyr_1.8.6            magrittr_2.0.2        R6_2.5.1             
##  [85] generics_0.1.1        DBI_1.1.2             withr_2.4.3          
##  [88] mgcv_1.8-38           pillar_1.7.0          fitdistrplus_1.1-6   
##  [91] survival_3.2-13       abind_1.4-5           tibble_3.1.6         
##  [94] future.apply_1.8.1    crayon_1.5.0          KernSmooth_2.23-20   
##  [97] utf8_1.2.2            spatstat.geom_2.3-1   plotly_4.10.0        
## [100] rmarkdown_2.11        grid_4.1.1            data.table_1.14.2    
## [103] digest_0.6.29         xtable_1.8-4          tidyr_1.1.4          
## [106] httpuv_1.6.5          munsell_0.5.0         bslib_0.3.1

  1. IPNP & Imagine Institute, Paris, France, ↩︎

LS0tCnRpdGxlOiAiRTExLUUxMiBTZXB0dW0gZGF0YXNldCIKYXV0aG9yOiAKICAtIEZyw6lkw6lyaWMgQ2F1c2VyZXReW0lQTlAgJiBJbWFnaW5lIEluc3RpdHV0ZSwgUGFyaXMsIEZyYW5jZSwgZnJlZGVyaWMuY2F1c2VyZXRAaW5zZXJtLmZyXSBbIVtdKGh0dHBzOi8vb3JjaWQub3JnL3NpdGVzL2RlZmF1bHQvZmlsZXMvaW1hZ2VzL29yY2lkXzE2eDE2LnBuZyldKGh0dHBzOi8vb3JjaWQub3JnLzAwMDAtMDAwMi0wNTQzLTQ5MzgpCiAKZGF0ZTogImByIGZvcm1hdChTeXMudGltZSgpLCAnJWQgJUIsICVZJylgIgpvdXRwdXQ6CiAgaHRtbF9kb2N1bWVudDoKICAgIGNvZGVfZG93bmxvYWQ6IHllcwogICAgZGZfcHJpbnQ6IHBhZ2VkCiAgICBoaWdobGlnaHQ6IGhhZGRvY2sKICAgIHRoZW1lOiBjb3NtbwogICAgbnVtYmVyX3NlY3Rpb25zOiB0cnVlCiAgICB0b2M6IHllcwogICAgdG9jX2RlcHRoOiA1CiAgICB0b2NfZmxvYXQ6CiAgICAgIGNvbGxhcHNlZDogeWVzCi0tLQoKYGBge2NzcywgZWNobz1GQUxTRX0KaDEgewogIGZvbnQtc2l6ZTogMzRweDsKICBtYXJnaW4tdG9wOiAycmVtOwogIG1hcmdpbi1ib3R0b206IDFyZW07CiAgY29sb3I6ICNlNjRkMDA7CiAgdGV4dC1kZWNvcmF0aW9uOiBub25lOwp9CmgxLnRpdGxlIHsKICBmb250LXNpemU6IDQwcHg7CiAgbWFyZ2luLXRvcDogMnJlbTsKICBtYXJnaW4tYm90dG9tOiAxcmVtOwogIHRleHQtYWxpZ246IGNlbnRlcjsKICB0ZXh0LWRlY29yYXRpb246IG5vbmU7CiAgY29sb3I6ICMwMDAwMDA7Cn0KaDIgewogIGZvbnQtc2l6ZTogMzBweDsKICBtYXJnaW4tdG9wOiAycmVtOwogIG1hcmdpbi1ib3R0b206IDFyZW07CiAgY29sb3I6ICMwMDAwMDA7Cn0KaDMgewogIGZvbnQtc2l6ZTogMjRweDsKICBtYXJnaW4tdG9wOiAycmVtOwogIG1hcmdpbi1ib3R0b206IDFyZW07CiAgY29sb3I6ICMwMDAwMDA7Cn0KaDQgewogIGZvbnQtc2l6ZTogMThweDsKICBtYXJnaW4tdG9wOiAycmVtOwogIG1hcmdpbi1ib3R0b206IDFyZW07CiAgY29sb3I6ICMwMDAwMDA7Cn0KaDUgewogIGZvbnQtc2l6ZTogMTZweDsKICBtYXJnaW4tdG9wOiAycmVtOwogIG1hcmdpbi1ib3R0b206IDFyZW07CiAgY29sb3I6ICMwMDAwMDA7Cn0KCnAgewogIGZvbnQtc2l6ZTogMTZweDsKfQpgYGAKCmBgYHtyIHNldHVwLCBpbmNsdWRlPUZBTFNFfQprbml0cjo6b3B0c19jaHVuayRzZXQoZWNobyA9IFRSVUUsIGZpZy5hbGlnbiA9ICdjZW50ZXInLCBtZXNzYWdlPUZBTFNFLCB3YXJuaW5nPUZBTFNFKQpgYGAKCgpUaGlzIGlzIGFuIGFuYWx5c2lzIG9mIGEgZGF0YXNldCBnZW5lcmF0ZWQgaW4gdGhlIGxhYiBjb250YWluaW5nIHNlcHR1bSBmcm9tIEUxMS41IFBHSy1DcmU7Um9zYTI2WUZQIGFuZCBFMTIuNSBEYngxLUNyZTtSb3NhMjZUb21hdG8gZW1icnlvcwpDZWxscyB3ZXJlIHByZXBhcmVkIGJ5IE1hdHRoaWV1IE1vcmVhdSAmIEZyw6lkw6lyaWMgQ2F1c2VyZXQgIApMaWJyYXJpZXMgd2VyZSBnZW5lcmF0ZWQgYnkgTWF0dGhpZXUgTW9yZWF1ICYgRnLDqWTDqXJpYyBDYXVzZXJldCAgClNlcXVlbmNpbmcgd2FzIGFjaGlldmVkIGF0IHRoZSBnZW5vbWljcyBwbGF0Zm9ybSBvZiBJbWFnaW5lICAKUmVhZHMgd2VyZSBhbGlnbmVkIG9uIHRoZSBtbTEwIGdlbm9tZSB0byB3aGljaCB3ZXJlIGFkZGVkOiAKLSBMYWNaLVNWNDAgIAotIFRvbWF0by1XUFJFLWJHSCAKCiMgTG9hZCBsaWJyYXJpZXMgIAoKYGBge3J9CmxpYnJhcnkoU2V1cmF0KQpsaWJyYXJ5KGRwbHlyKQpsaWJyYXJ5KHBhdGNod29yaykKbGlicmFyeShjb3dwbG90KQpsaWJyYXJ5KGdncGxvdDIpCmxpYnJhcnkoZ2dFeHRyYSkKCmxpYnJhcnkoTWF0cml4KQpsaWJyYXJ5KFJDb2xvckJyZXdlcikKbGlicmFyeSh2aXJpZGlzKQpsaWJyYXJ5KHdlc2FuZGVyc29uKQpsaWJyYXJ5KE1ldEJyZXdlcikKCgojIFNldCBnZ3Bsb3QgdGhlbWUgYXMgY2xhc3NpYwp0aGVtZV9zZXQodGhlbWVfY2xhc3NpYygpKQpgYGAKCiMgTG9hZCB0aGUgZGF0YXNldCBhbmQgY2FsY3VsYXRlIFFDIG1ldHJpY3MKCiMjIEluaXRpYWxpemUgYSBTZXVyYXQgb2JqZWN0IGZyb20gdGhlIHJhdyBmaWx0ZXJlZCBnZW5lL2JjIG1hdHJpeAoKYGBge3IgY2FjaGUgPSBUUlVFfQojIExvYWQgdGhlIHJhdyBmaWx0ZXJlZF9nZW5lX2JjX21hdHJpeCBvdXRwdXRlZCBieSBDZWxsIFJhbmdlcgpDb3VudGRhdGEgPC0gUmVhZDEwWChkYXRhLmRpciA9ICIvc2hhcmVkL2lmYnN0b3IxL2hvbWUvZmNhdXNlcmV0L1NlcHR1bS9maWx0ZXJlZF9nZW5lX2JjX21hdHJpY2VzLyIpCgojIEluaXRpYWxpemUgdGhlIFNldXJhdCBvYmplY3QKU2VwdHVtIDwtIENyZWF0ZVNldXJhdE9iamVjdChjb3VudHMgPSBDb3VudGRhdGEsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBtaW4uY2VsbHMgPSAzLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgbWluLmZlYXR1cmVzID0gODAwLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgcHJvamVjdCA9ICJTZXB0dW0iKQoKU2VwdHVtJEJhcmNvZGVzIDwtIGNvbG5hbWVzKFNlcHR1bSkKCmRpbShTZXB0dW0pCgpybShDb3VudGRhdGEpCmBgYAoKIyMgQ2FsY3VsYXRlIHBlcmNlbnRhZ2Ugb2YgbWl0b2Nob25kcmlhbCBhbmQgcmlib3NvbWFsIGNvdW50cwoKYGBge3J9CiMgUGVyY2VudCBvZiBtaXRvY2hvbmRyaWFsIGNvdW50cwpTZXB0dW1bWyJwZXJjZW50Lm10Il1dIDwtIFBlcmNlbnRhZ2VGZWF0dXJlU2V0KFNlcHR1bSwgcGF0dGVybiA9ICJebXQtIikKCiMgUGVyY2VudCBvZiByaWJvc29tYWwgY291bnRzClNlcHR1bVtbInBlcmNlbnQucmIiXV0gPC0gUGVyY2VudGFnZUZlYXR1cmVTZXQoU2VwdHVtLCBwYXR0ZXJuID0gIiheUnBsfF5ScHN8Xk1ycCkiKQpgYGAKCiMjIENlbGwgUXVhbGl0eSBhY2NvcmRpbmcgdG8gdGhlIG1pdG9jaG9uZHJpYWwgUk5BIHBlcmNlbnRhZ2UgaW4gdGhlIGNlbGxzCgpgYGB7cn0KIyBGaWx0ZXIgY2VsbHMgYmFzZWQgb24gdGhlc2UgdGhyZXNob2xkcwpDZWxsLlFDLlN0YXQgPC0gU2VwdHVtQG1ldGEuZGF0YQptYXgubWl0by50aHIgPC0gbWVkaWFuKENlbGwuUUMuU3RhdCRwZXJjZW50Lm10KSArIDMqbWFkKENlbGwuUUMuU3RhdCRwZXJjZW50Lm10KQptaW4ubWl0by50aHIgPC0gbWVkaWFuKENlbGwuUUMuU3RhdCRwZXJjZW50Lm10KSAtIDMqbWFkKENlbGwuUUMuU3RhdCRwZXJjZW50Lm10KQpDZWxsLlFDLlN0YXQgPC0gQ2VsbC5RQy5TdGF0ICU+JSBmaWx0ZXIocGVyY2VudC5tdCA8IG1heC5taXRvLnRocikgJT4lIGZpbHRlcihwZXJjZW50Lm10ID4gbWluLm1pdG8udGhyKQoKU2VwdHVtQG1ldGEuZGF0YSRDZWxsLnF1YWxpdHkgPC0gaWZlbHNlKFNlcHR1bUBtZXRhLmRhdGEkcGVyY2VudC5tdCA+IG1pbi5taXRvLnRociAmIFNlcHR1bUBtZXRhLmRhdGEkcGVyY2VudC5tdCA8IG1heC5taXRvLnRociwgIkhpZ2ggUXVhbGl0eSIsICJMb3cgUXVhbGl0eSIpCgp0YWJsZShTZXB0dW0kQ2VsbC5xdWFsaXR5KQoKcm0oQ2VsbC5RQy5TdGF0LCBtYXgubWl0by50aHIsIG1pbi5taXRvLnRocikKYGBgCgojIyBQbG90IGJhc2ljIFFDIG1ldHJpY3MKCmBgYHtyIGZpZy5kaW09YygyMCwxMCl9CiNWaW9saW4gcGxvdCAKVmxuUGxvdChTZXB0dW0sIGZlYXR1cmVzID0gYygibkZlYXR1cmVfUk5BIiwgIm5Db3VudF9STkEiLCAicGVyY2VudC5tdCIsICJwZXJjZW50LnJiIiksIG5jb2wgPSA0LCBncm91cC5ieT0iQ2VsbC5xdWFsaXR5IikKYGBgCgoKIyMjIFBsb3QgbW9yZSBRQyBtZXRyaWNzCgpgYGB7ciBmaWcuZGltPWMoMjAsIDcpfQojIFJlbGF0aW9uIGJldHdlZW4gbkNvdW50X1JOQSBhbmQgbkZlYXR1cmVzX1JOQSBkZXRlY3RlZCB3aXRoIGNlbGwgcXVhbGl0eSBwYXJhbWV0ZXIKcDEgPC0gZ2dwbG90KFNlcHR1bUBtZXRhLmRhdGEsIGFlcyh4PW5Db3VudF9STkEsIHk9bkZlYXR1cmVfUk5BKSkgKyBnZW9tX3BvaW50KGFlcyhjb2xvcj1DZWxsLnF1YWxpdHkpLCBzaXplPTAuMSkgKyBnZW9tX3Ntb290aChtZXRob2Q9ImxtIikKcDEgPC0gZ2dNYXJnaW5hbChwMSwgdHlwZSA9ICJoaXN0b2dyYW0iLCBmaWxsPSJsaWdodGdyZXkiKQoKcDIgPC0gZ2dwbG90KFNlcHR1bUBtZXRhLmRhdGEsIGFlcyh4PWxvZzEwKG5Db3VudF9STkEpLCB5PWxvZzEwKG5GZWF0dXJlX1JOQSkpKSArIGdlb21fcG9pbnQoYWVzKGNvbG9yPUNlbGwucXVhbGl0eSksIHNpemU9MC4xKSArIGdlb21fc21vb3RoKG1ldGhvZD0ibG0iKQpwMiA8LSBnZ01hcmdpbmFsKHAyLCB0eXBlID0gImhpc3RvZ3JhbSIsIGZpbGw9ImxpZ2h0Z3JleSIpCgojIFJlbGF0aW9uIGJldHdlZW4gbkZlYXR1cmVzX1JOQSBhbmQgdGhlIG1pdG9jaG9uZHJpYWwgUk5BIHBlcmNlbnRhZ2UgZGV0ZWN0ZWQgd2l0aCBjZWxsIHF1YWxpdHkgcGFyYW1ldGVyCnAzIDwtIGdncGxvdChTZXB0dW1AbWV0YS5kYXRhLCBhZXMoeD1uRmVhdHVyZV9STkEsIHk9cGVyY2VudC5tdCwgY29sb3I9Q2VsbC5xdWFsaXR5KSkgKyBnZW9tX3BvaW50KHNpemU9MC4xKQpwMyA8LSBnZ01hcmdpbmFsKHAzLCB0eXBlID0gImhpc3RvZ3JhbSIsIGZpbGw9ImxpZ2h0Z3JleSIsIGJpbnM9MTAwKSAKICAgIApwbG90X2dyaWQocGxvdGxpc3QgPSBsaXN0KHAxLHAyLHAzKSwgbmNvbD0zLCBhbGlnbj0naCcsIHJlbF93aWR0aHMgPSBjKDEsIDEsIDEpKQoKcm0ocDEsIHAyLCBwMykKYGBgCgojIyBDZWxsIEN5Y2xlIFNjb3JpbmcKCmBgYHtyfQojIEFzc2lnbiBjZWxsLWN5Y2xlIHNjb3JlcwpzLmdlbmVzIDwtIGMoIk1jbTUiLCAiUGNuYSIsICJUeW01IiwgIkZlbjEiLCAiTWNtMiIsICJNY200IiwgIlJybTEiLCAiVW5nIiwgIkdpbnMyIiwgIk1jbTYiLCAiQ2RjYTciLCAiRHRsIiwgIlByaW0xIiwgIlVocmYxIiwgIk1sZjFpcCIsICJIZWxscyIsICJSZmMyIiwgIlJhcDIiLCAiTmFzcCIsICJSYWQ1MWFwMSIsICJHbW5uIiwgIldkcjc2IiwgIlNsYnAiLCAiQ2NuZTIiLCAiVWJyNyIsICJQb2xkMyIsICJNc2gyIiwgIkF0YWQyIiwgIlJhZDUxIiwgIlJybTIiLCAiQ2RjNDUiLCAiQ2RjNiIsICJFeG8xIiwgIlRpcGluIiwgIkRzY2MxIiwgIkJsbSIsICIgQ2FzcDhhcDIiLCAiVXNwMSIsICJDbHNwbiIsICJQb2xhMSIsICJDaGFmMWIiLCAiQnJpcDEiLCAiRTJmOCIpCmcybS5nZW5lcyA8LSBjKCJIbWdiMiIsICJEZGsxIiwiTnVzYXAxIiwgIlViZTJjIiwgIkJpcmM1IiwgIlRweDIiLCAiVG9wMmEiLCAiTmRjODAiLCAiQ2tzMiIsICJOdWYyIiwgIkNrczFiIiwgIk1raTY3IiwgIlRtcG8iLCAiIENlbnBrIiwgIlRhY2MzIiwgIkZhbTY0YSIsICJTbWM0IiwgIkNjbmIyIiwgIkNrYXAybCIsICJDa2FwMiIsICJBdXJrYiIsICJCdWIxIiwgIktpZjExIiwgIkFucDMyZSIsICJUdWJiNGIiLCAiR3RzZTEiLCAia2lmMjBiIiwgIkhqdXJwIiwgIkNkY2EzIiwgIkhuMSIsICJDZGMyMCIsICJUdGsiLCAiQ2RjMjVjIiwgImtpZjJjIiwgIlJhbmdhcDEiLCAiTmNhcGQyIiwgIkRsZ2FwNSIsICJDZGNhMiIsICJDZGNhOCIsICJFY3QyIiwgIktpZjIzIiwgIkhtbXIiLCAiQXVya2EiLCAiUHNyYzEiLCAiQW5sbiIsICJMYnIiLCAiQ2thcDUiLCAiQ2VucGUiLCAiQ3RjZiIsICJOZWsyIiwgIkcyZTMiLCAiR2FzMmwzIiwgIkNieDUiLCAiQ2VucGEiKQoKU2VwdHVtIDwtIENlbGxDeWNsZVNjb3JpbmcoU2VwdHVtLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgIHMuZmVhdHVyZXMgPSBzLmdlbmVzLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgIGcybS5mZWF0dXJlcyA9IGcybS5nZW5lcywKICAgICAgICAgICAgICAgICAgICAgICAgICAgICBzZXQuaWRlbnQgPSBUKQp0YWJsZShTZXB0dW0kUGhhc2UpCnJtKHMuZ2VuZXMsIGcybS5nZW5lcykKYGBgCgoKIyBOb3JtYWxpemUgY291bnRzCgpgYGB7cn0KIyBMb2dOb3JtYWxpemUgdGhlIGdlbmUgZXhwcmVzc2lvbiBtYXRyaXggKGdsb2JhbC1zY2FsaW5nIG5vcm1hbGl6YXRpb24gbWV0aG9kKQpTZXB0dW0gPC0gTm9ybWFsaXplRGF0YShTZXB0dW0sIG5vcm1hbGl6YXRpb24ubWV0aG9kID0gIkxvZ05vcm1hbGl6ZSIsIHNjYWxlLmZhY3RvciA9IDEwMDAwKQoKYGBgCgoKIyBJZGVudGlmaWNhdGlvbiBvZiBoaWdobHkgdmFyaWFibGUgZmVhdHVyZXMgKGZlYXR1cmUgc2VsZWN0aW9uKQoKYGBge3IgZmlnLmRpbT1jKDIwLCAxMCl9ClNlcHR1bSA8LSBGaW5kVmFyaWFibGVGZWF0dXJlcyhTZXB0dW0sIHNlbGVjdGlvbi5tZXRob2QgPSAidnN0IiwgbmZlYXR1cmVzID0gMjAwMCkKCiMgSWRlbnRpZnkgdGhlIDEwIG1vc3QgaGlnaGx5IHZhcmlhYmxlIGdlbmVzCnRvcDIwIDwtIGhlYWQoVmFyaWFibGVGZWF0dXJlcyhTZXB0dW0pLCAyMCkKCiMgUGxvdCB2YXJpYWJsZSBmZWF0dXJlcyB3aXRoIGFuZCB3aXRob3V0IGxhYmVscwpwbG90MSA8LSBWYXJpYWJsZUZlYXR1cmVQbG90KFNlcHR1bSkgKyB0aGVtZShsZWdlbmQucG9zaXRpb24gPSAidG9wIikKcGxvdDIgPC0gTGFiZWxQb2ludHMocGxvdCA9IHBsb3QxLCBwb2ludHMgPSB0b3AyMCwgcmVwZWwgPSBUKSArIHRoZW1lKGxlZ2VuZC5wb3NpdGlvbiA9ICJub25lIikKcGxvdF9ncmlkKHBsb3RsaXN0ID0gbGlzdChwbG90MSxwbG90MiksIG5jb2w9MiwgYWxpZ249J2gnLCByZWxfd2lkdGhzID0gYygxLCAxKSkKCgpybSh0b3AyMCwgcGxvdDEsIHBsb3QyKQpgYGAKCiMgU2NhbGluZyB0aGUgZGF0YQoKYGBge3J9CiMgTGluZWFyIHRyYW5zZm9ybWF0aW9uIDogUHJlLXByb2Nlc3Npbmcgc3RlcCBmb3IgZGltZW5zaW9uYWwgcmVkdWN0aW9uIGxpa2UgUENBIApTZXB0dW0gPC0gU2NhbGVEYXRhKFNlcHR1bSkKYGBgCgojIFBlcmZvcm0gbGluZWFyIGRpbWVuc2lvbmFsIHJlZHVjdGlvbgoKYGBge3J9ClNlcHR1bSA8LSBSdW5QQ0EoU2VwdHVtLCBmZWF0dXJlcyA9IFZhcmlhYmxlRmVhdHVyZXMob2JqZWN0ID0gU2VwdHVtKSkKIyBFeGFtaW5lIGFuZCB2aXN1YWxpemUgUENBIHJlc3VsdHMgYSBmZXcgZGlmZmVyZW50IHdheXMKcHJpbnQoU2VwdHVtW1sicGNhIl1dLCBkaW1zID0gMTo1LCBuZmVhdHVyZXMgPSA1KQoKVml6RGltTG9hZGluZ3MoU2VwdHVtLCBkaW1zID0gMToyLCByZWR1Y3Rpb24gPSAicGNhIikKCkRpbUhlYXRtYXAoU2VwdHVtLCBkaW1zID0gMTo2LCBjZWxscyA9IDUwMCwgYmFsYW5jZWQgPSBUUlVFKQoKYGBgCgojIERldGVybWluZSB0aGUgJ2RpbWVuc2lvbmFsaXR5JyBvZiB0aGUgZGF0YXNldAoKYGBge3IgY2FjaGUgPSBUUlVFfQojICBNb3JlIGFwcHJveGltYXRlIHRlY2huaXF1ZXMgc3VjaCBhcyB0aG9zZSBpbXBsZW1lbnRlZCBpbiBFbGJvd1Bsb3QoKSBjYW4gYmUgdXNlZCB0byByZWR1Y2UgY29tcHV0YXRpb24gdGltZQpTZXB0dW0gPC0gSmFja1N0cmF3KFNlcHR1bSwgbnVtLnJlcGxpY2F0ZSA9IDEwMCkKU2VwdHVtIDwtIFNjb3JlSmFja1N0cmF3KFNlcHR1bSwgZGltcyA9IDE6MjApCgojIEphY2tTdHJhd1Bsb3QKSmFja1N0cmF3UGxvdChTZXB0dW0sIGRpbXMgPSAxOjIwKQoKI0VsYm93UGxvdApFbGJvd1Bsb3QoU2VwdHVtKQpgYGAKCiMgUnVuIG5vbi1saW5lYXIgZGltZW5zaW9uYWwgcmVkdWN0aW9uIChVTUFQKQoKYGBge3IgY2FjaGU9VFJVRX0KU2VwdHVtIDwtIFJ1blVNQVAoU2VwdHVtLCBkaW1zID0gMToyMCkKRGltUGxvdChTZXB0dW0sIHJlZHVjdGlvbiA9ICJ1bWFwIiwgbGFiZWwgPSBUUlVFLCBsYWJlbC5zaXplID0gMywgcHQuc2l6ZSA9IDAuMSkgKyBOb0F4ZXMoKQpgYGAKCiMgQ2x1c3RlciB0aGUgY2VsbHMKCmBgYHtyIGNhY2hlPVRSVUV9ClNlcHR1bSA8LSBGaW5kTmVpZ2hib3JzKFNlcHR1bSwgZGltcyA9IDE6MjApClNlcHR1bSA8LSBGaW5kQ2x1c3RlcnMoU2VwdHVtLCByZXNvbHV0aW9uID0gMS41KQoKIyBWaXN1YWxpemUgY2x1c3RlcnMKRGltUGxvdChTZXB0dW0sIHJlZHVjdGlvbiA9ICJ1bWFwIiwgbGFiZWwgPSBUUlVFLCBsYWJlbC5zaXplID0gMywgcHQuc2l6ZSA9IDAuMSkgKyBOb0F4ZXMoKSArIGdndGl0bGUocGFzdGUoZGltKFNlcHR1bSlbMl0sICIgc2VwdHVtIGNlbGxzIikpIAoKYGBgCgojIFJlbW92ZSBsb3cgcXVhbGl0eSwgYmxvb2QgYW5kIG1lbmluZ2VzIGNlbGxzCgpgYGB7ciBjYWNoZT1UUlVFfQpEaW1QbG90KFNlcHR1bSwgcmVkdWN0aW9uID0gInVtYXAiLCBsYWJlbCA9IFRSVUUsIGxhYmVsLnNpemUgPSAzLCBwdC5zaXplID0gMC4xLCBncm91cC5ieT0iQ2VsbC5xdWFsaXR5IikgKyBOb0F4ZXMoKQoKRmVhdHVyZVBsb3QoU2VwdHVtLCBmZWF0dXJlcyA9IGMoIkhiYS1hMSIsICJDb2wzYTEiKSwgb3JkZXIgPSBULCAKICAgICAgICAgICAgY29scyA9IGMoImdyZXk5MCIsIGJyZXdlci5wYWwoOSwiWWxPclJkIikpKSAmIE5vTGVnZW5kKCkgJiBOb0F4ZXMoKQoKU2VwdHVtIDwtIHN1YnNldChTZXB0dW0sIGlkZW50cyA9IGMoOCwgMjAsIDIyKSwgaW52ZXJ0ID0gVFJVRSkKCkRpbVBsb3QoU2VwdHVtLCByZWR1Y3Rpb24gPSAidW1hcCIsIGxhYmVsID0gVFJVRSwgbGFiZWwuc2l6ZSA9IDMsIHB0LnNpemUgPSAwLjEpICsgTm9BeGVzKCkgKyBnZ3RpdGxlKHBhc3RlKGRpbShTZXB0dW0pWzJdLCAiIGNlbGxzIGFmdGVyIGZpbHRlcmluZyIpKSAKCmBgYAoKIyBFeHBvcnQgZmlsZXMgZm9yIFNwcmluZwoKIyMgRXhwb3J0IHJhdyBleHByZXNzaW9uIG1hdHJpeCBhbmQgZ2VuZSBsaXN0IGZvciBzcHJpbmcgcGxvdCBnZW5lcmF0aW9uCmBgYHtyIGNhY2hlID0gVFJVRX0KIyBHZW5lcmF0ZSBTcHJpbmcgZGltZW5zaW9uYWxpdHkgcmVkdWN0aW9uCkV4cHJzTWF0cml4IDwtIGFzLm1hdHJpeChHZXRBc3NheURhdGEoU2VwdHVtKSkKZXhwckRhdGEgPC0gTWF0cml4KEV4cHJzTWF0cml4LCBzcGFyc2UgPSBUUlVFKQp3cml0ZU1NKGV4cHJEYXRhLCAiRXhwckRhdGEubXR4IikKCkdlbmVsaXN0IDwtIHJvdy5uYW1lcyhFeHByc01hdHJpeCkKd3JpdGUudGFibGUoR2VuZWxpc3QsICJHZW5lbGlzdC5jc3YiLCBzZXA9Ilx0IiwgY29sLm5hbWVzID0gRiwgcm93Lm5hbWVzID0gRikKcm0oRXhwcnNNYXRyaXgsIGV4cHJEYXRhLCBHZW5lbGlzdCkKCmBgYAoKIyMgRXhwb3J0IGNvbnRpbnVvdXMgbWV0YWRhdGEKYGBge3J9ClMuU2NvcmUgPC0gYygiUy5TY29yZSIsU2VwdHVtQG1ldGEuZGF0YSRTLlNjb3JlKQpTLlNjb3JlIDwtIHBhc3RlKFMuU2NvcmUsIHNlcD0iLCIsIGNvbGxhcHNlPSIsIikKCkcyTS5TY29yZSA8LSBjKCJHMk0uU2NvcmUiLFNlcHR1bUBtZXRhLmRhdGEkRzJNLlNjb3JlKQpHMk0uU2NvcmUgPC0gcGFzdGUoRzJNLlNjb3JlLCBzZXA9IiwiLCBjb2xsYXBzZT0iLCIpCgpQZXJjZW50Lm10IDwtIGMoIlBlcmNlbnQubXQiLCBTZXB0dW0kcGVyY2VudC5tdCkKUGVyY2VudC5tdCA8LSBwYXN0ZShQZXJjZW50Lm10LCBzZXAgPSAiLCIsIGNvbGxhcHNlID0gIiwiKQoKUGVyY2VudC5yYiA8LSBjKCJQZXJjZW50LnJiIiwgU2VwdHVtJHBlcmNlbnQucmIpClBlcmNlbnQucmIgPC0gcGFzdGUoUGVyY2VudC5yYiwgc2VwID0gIiwiLCBjb2xsYXBzZSA9ICIsIikKCm5Db3VudCA8LSBjKCJuQ291bnQiLCBTZXB0dW0kbkNvdW50X1JOQSkKbkNvdW50IDwtIHBhc3RlKG5Db3VudCwgc2VwID0gIiwiLCBjb2xsYXBzZSA9ICIsIikgCgpuRmVhdHVyZSA8LSBjKCJuRmVhdHVyZSIsIFNlcHR1bSRuRmVhdHVyZV9STkEpCm5GZWF0dXJlIDwtIHBhc3RlKG5GZWF0dXJlLCBzZXAgPSAiLCIsIGNvbGxhcHNlID0gIiwiKSAKCkNvbG9yVHJhY2sgPC0gcmJpbmQoUy5TY29yZSwgRzJNLlNjb3JlLCBQZXJjZW50Lm10LCBQZXJjZW50LnJiLCBuQ291bnQsIG5GZWF0dXJlKQp3cml0ZS50YWJsZShDb2xvclRyYWNrLCAiQ29sb3JUcmFjay5jc3YiLCBxdW90ZSA9Riwgcm93Lm5hbWVzID0gRiwgY29sLm5hbWVzID0gRikKCnJtKFMuU2NvcmUsIEcyTS5TY29yZSwgUGVyY2VudC5tdCwgUGVyY2VudC5yYiwgbkNvdW50LCBuRmVhdHVyZSwgQ29sb3JUcmFjaykKYGBgCgojIyBFeHBvcnQgZGlzY3JldGUgbWV0YWRhdGEKYGBge3J9CgpTZXVyYXQuY2x1c3RlcnMgPC0gYygiU2V1cmF0IENsdXN0ZXJzIiwgcGFzdGUwKCJDbHVzdGVyIixhcy5jaGFyYWN0ZXIoU2VwdHVtQG1ldGEuZGF0YSRzZXVyYXRfY2x1c3RlcnMpKSkKU2V1cmF0LmNsdXN0ZXJzIDwtIHBhc3RlKFNldXJhdC5jbHVzdGVycywgc2VwPSIsIiwgY29sbGFwc2U9IiwiKQoKUGhhc2UgPC0gYygiUGhhc2UiLCBTZXB0dW1AbWV0YS5kYXRhJFBoYXNlKQpQaGFzZSA8LSBwYXN0ZShQaGFzZSwgc2VwPSIsIiwgY29sbGFwc2U9IiwiKQoKUXVhbGl0eSA8LSBjKCJDZWxsIFF1YWxpdHkiLCBTZXB0dW0kQ2VsbC5xdWFsaXR5KSAKUXVhbGl0eSA8LSBwYXN0ZShRdWFsaXR5LCBzZXAgPSAiLCIsIGNvbGxhcHNlID0gIiwiKSAKCkNlbGxncm91cGluZyA8LSByYmluZChTZXVyYXQuY2x1c3RlcnMsIFBoYXNlLCBRdWFsaXR5KQp3cml0ZS50YWJsZShDZWxsZ3JvdXBpbmcsICJDZWxsZ3JvdXBpbmcuY3N2IiwgcXVvdGUgPUYsIHJvdy5uYW1lcyA9IEYsIGNvbC5uYW1lcyA9IEYpCgpybShDZWxsZ3JvdXBpbmcsIFNldXJhdC5jbHVzdGVycywgUGhhc2UsIFF1YWxpdHkpCmBgYAoKRXhwckRhdGEubXR4LCBHZW5lbGlzdC5jc3YsIENvbG9yVHJhY2suY3N2IGFuZCBDZWxsZ3JvdXBpbmcuY3N2IGFyZSB0aGVuIHVzZWQgYXMgaW5wdXQgZm9yIHRoZSBTcHJpbmcgQXBwCkNlbGwgY29vcmRpbmF0ZXMgb2YgdGhlIFNwcmluZyBkaW1lbnNpb25hbGl0eSByZWR1Y3Rpb24gYXMgd2VsbCBhcyBkb3VibGV0IHNjb3JlIGFyZSB0aGVuIGRvd25sb2FkZWQKCiMgSW1wb3J0IFNwcmluZyBkb3VibGV0IHNjb3JlIChzY3J1YmJsZXQpIGFuZCByZW1vdmUgZG91YmxldHMKYGBge3IgZmlnLmRpbT1jKDYsIDYpfQpkb3VibGV0LnNjb3JlIDwtIHJlYWQudGFibGUoIi9zaGFyZWQvaWZic3RvcjEvaG9tZS9mY2F1c2VyZXQvU2VwdHVtL2RvdWJsZXRfcmVzdWx0cy50c3YiLCBoZWFkZXIgPSBUKQpkb3VibGV0LnNjb3JlIDwtIGZpbHRlcihkb3VibGV0LnNjb3JlLCBPYnNlcnZlZF9vcl9TaW11bGF0ZWQgPT0gIk9ic2VydmVkIikKcm93bmFtZXMoZG91YmxldC5zY29yZSkgPC0gU2VwdHVtJEJhcmNvZGVzClNlcHR1bUBtZXRhLmRhdGEkZG91YmxldC5zY29yZSA8LWRvdWJsZXQuc2NvcmUkU2NvcmUKVmxuUGxvdChvYmplY3QgPSBTZXB0dW0sIGZlYXR1cmVzID0gImRvdWJsZXQuc2NvcmUiLCBwdC5zaXplID0gMC4yKSArIGdlb21faGxpbmUoeWludGVyY2VwdCA9IDAuNCwgbGluZXR5cGU9ImRhc2hlZCIpICsgRmVhdHVyZVBsb3QoU2VwdHVtLCBmZWF0dXJlcyA9IGMoImRvdWJsZXQuc2NvcmUiKSwgb3JkZXIgPSBULAogICAgICAgICAgICBjb2xzID0gYygiZ3JleTkwIiwgYnJld2VyLnBhbCg5LCJZbE9yUmQiKSkpCgoKU2VwdHVtIDwtIHN1YnNldChTZXB0dW0sIHN1YnNldCA9IGRvdWJsZXQuc2NvcmUgPCAwLjQpCgpEaW1QbG90KFNlcHR1bSwgcmVkdWN0aW9uID0gInVtYXAiLCBsYWJlbCA9IFRSVUUsIGxhYmVsLnNpemUgPSAzLCBwdC5zaXplID0gMC4xKSArIE5vQXhlcygpICsgZ2d0aXRsZShwYXN0ZShkaW0oU2VwdHVtKVsyXSwgIiBjZWxscyBhZnRlciBkb3VibGV0cyByZW1vdmFsIikpIAoKYGBgCgoKIyBJbXBvcnQgU3ByaW5nIGNvb3JkaW5hdGVzCmBgYHtyIGZpZy5kaW09Yyg2LCA2KX0KQ29vcmRpbmF0ZXMgPC0gcmVhZC50YWJsZSgiL3NoYXJlZC9pZmJzdG9yMS9ob21lL2ZjYXVzZXJldC9TZXB0dW0vY29vcmRpbmF0ZXMudHh0Iiwgc2VwID0gIiwiLCBoZWFkZXIgPSBGKVssYygyLDMpXQpyb3duYW1lcyhDb29yZGluYXRlcykgPC0gU2VwdHVtJEJhcmNvZGVzCmNvbG5hbWVzKENvb3JkaW5hdGVzKSA8LSBwYXN0ZTAoIlNwcmluZ18iLCAxOjIpCgojIFdlIHdpbGwgbm93IHN0b3JlIHRoaXMgYXMgYSBjdXN0b20gZGltZW5zaW9uYWwgcmVkdWN0aW9uIDogc3ByaW5nClNlcHR1bVtbIlNwcmluZyJdXSA8LSBDcmVhdGVEaW1SZWR1Y09iamVjdChlbWJlZGRpbmdzID0gYXMubWF0cml4KENvb3JkaW5hdGVzKSwga2V5ID0gIlNwcmluZ18iLCBhc3NheSA9IERlZmF1bHRBc3NheShTZXB0dW0pKQoKIyBTeW1tZXRyeSB0cmFuc2Zvcm0gb2YgdGhlIGNvb3JkaW5hdGVzCgpTcHJpbmcuU3ltIDwtIGZ1bmN0aW9uKHgpewogIHggPSBhYnMobWF4KENvb3JkaW5hdGVzWywyXSkteCkKIH0KCkNvb3JkaW5hdGVzWywyXSA8LSBzYXBwbHkoQ29vcmRpbmF0ZXNbLDJdICwgZnVuY3Rpb24oeCkgU3ByaW5nLlN5bSh4KSkKClNlcHR1bVtbIlNwcmluZyJdXSA8LSBDcmVhdGVEaW1SZWR1Y09iamVjdChlbWJlZGRpbmdzID0gYXMubWF0cml4KENvb3JkaW5hdGVzKSwga2V5ID0gIlNwcmluZ18iLCBhc3NheSA9IERlZmF1bHRBc3NheShTZXB0dW0pKQoKcm0oQ29vcmRpbmF0ZXMsIGRvdWJsZXQuc2NvcmUpCgoKIyBTcHJpbmcgdmlzdWFsaXphdGlvbiAKRGltUGxvdChTZXB0dW0sIHJlZHVjdGlvbiA9ICJTcHJpbmciLCBwdC5zaXplID0gMC4yLCBsYWJlbCA9IFQsIGxhYmVsLnNpemUgPSAzKSArIE5vQXhlcygpICsgTm9MZWdlbmQoKQoKRmVhdHVyZVBsb3QoU2VwdHVtLAogICAgICAgICAgICBmZWF0dXJlcyA9IGMoIkVvbWVzIiwgIlRicjEiLCAiSXNsMSIsICJUcnA3MyIsICJPbmVjdXQyIiwgIkRieDEiLCAiZHRUb21hdG8iLCAiUGNkaDgiLCAiU3BvbjEiKSwKICAgICAgICAgICAgcmVkdWN0aW9uID0gIlNwcmluZyIsCiAgICAgICAgICAgIG5jb2wgPSAzLAogICAgICAgICAgICBvcmRlciA9IFQsCiAgICAgICAgICAgIGNvbHMgPSBjKCJncmV5OTAiLCBicmV3ZXIucGFsKDksIllsR25CdSIpKSkgICYgTm9MZWdlbmQoKSAmIE5vQXhlcygpCgoKCmBgYAoKIyBTYXZlIG9iamVjdCAgIAoKYGBge3J9CgpzYXZlUkRTKFNlcHR1bSwgIi9zaGFyZWQvaWZic3RvcjEvaG9tZS9mY2F1c2VyZXQvU2VwdHVtL1NlcHR1bS5SRFMiKQoKYGBgCgoKIyBTZXNzaW9uIEluZm8KCmBgYHtyfQojZGF0ZQpmb3JtYXQoU3lzLnRpbWUoKSwgIiVkICVCLCAlWSwgJUgsJU0iKQoKI1BhY2thZ2VzIHVzZWQKc2Vzc2lvbkluZm8oKQpgYGAKCgoKCgoKCgoKCgoKCg==